package com.vtquang.mygame2d.actor;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.maps.tiled.TiledMap;
import com.badlogic.gdx.maps.tiled.TiledMapTileLayer;
import com.badlogic.gdx.maps.tiled.TiledMapTileLayer.Cell;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Pool;

public class Supermaric extends MySprite2D{

	/**
	 * The Enum State.
	 */
	enum State {

		/** The Standing. */
		Standing,
		/** The Walking. */
		Walking,
		/** The Jumping. */
		Jumping
	}
	
	/** The max velocity. */
	static float MAX_VELOCITY = 10f;

	/** The jump velocity. */
	static float JUMP_VELOCITY = 40f;

	/** The damping. */
	static float DAMPING = 0.87f;
	
	/** The Constant GRAVITY. */
	private static final float GRAVITY = -2.5f; 
	
	/** Van toc **/
	public Vector2 velocity;
	
	/** State **/
	State state = State.Walking;  
	
	/** The faces right. */
	boolean facesRight = true;

	/** The grounded. */
	boolean isGrounded = false;
	
	/** The stand. */
	private Animation stand;

	/** The walk. */
	private Animation walk;

	/** The jump. */
	private Animation jump;
	
	/** Map */
	private TiledMap map;

	private float totalTime;

	/** The rect pool. */
	private Pool<Rectangle> rectPool = new Pool<Rectangle>() {
		@Override
		protected Rectangle newObject() {
			return new Rectangle();
		}
	};
	
	public Supermaric(Texture texture, TiledMap map) {
		super(texture);
		this.map = map;
		
		TextureRegion[] regions = TextureRegion.split(this.texture, 18, 26)[0];
		stand = new Animation(0, regions[0]);
		jump = new Animation(0, regions[1]);
		walk = new Animation(0.15f, regions[2], regions[3], regions[4]);
		walk.setPlayMode(Animation.LOOP_PINGPONG);
		
		this.size.x = 1 / 16f * regions[0].getRegionWidth();
		this.size.y = 1 / 16f * regions[0].getRegionHeight();
		
		this.velocity = new Vector2(0, 0);
		this.totalTime = 0;
	}
	
	@Override
	public void update(float gameTime) {  
		if (gameTime == 0) return;
		
		updateInput(gameTime);
		
		// trong luc
		this.velocity.add(0, GRAVITY);
		
		// luc ma sat
		this.velocity.x *= DAMPING; 
		if(Math.abs(velocity.x) < 1){
			this.velocity.x = 0;
			if(isGrounded){
				this.state = State.Standing;
			}
		} 
		
		this.velocity.scl(gameTime);
		
		Rectangle boundSuper = rectPool.obtain();
		boundSuper.set(this.position.x + velocity.x, position.y + velocity.y, size.x, size.y);
		
		// Kiem tra co vat can theo phuong ngang
		int startX, startY, endX, endY;
		if(velocity.x > 0){ // dang di sang phai
			startX = endX = (int) (position.x + size.x + velocity.x);
		}else{ // dang di sang trai
			startX = endX = (int) (position.x + velocity.x);
		}
		if(velocity.y > 0){ // dang di len
			startY = endY = (int) (position.y + size.y);
		}else{ // dang di xuong
			startY = endY = (int) (position.y);
		} 
		 
		Array<Rectangle> tiles = getTiles(startX, startY, endX, endY);
		for (Rectangle tile : tiles) {
			if (boundSuper.overlaps(tile)) {
				this.velocity.x = 0;
				break;
			}
		} 
		
		// Kiem tra co vat can theo phuong dung   
		for (Rectangle tile : tiles) {
			if (boundSuper.overlaps(tile)) { 
				if (this.velocity.y > 0) {
					this.position.y = tile.y - size.y;
					TiledMapTileLayer layer = (TiledMapTileLayer) map.getLayers().get(1);
					layer.setCell((int) tile.x, (int) tile.y, null);
				} else {
					position.y = tile.y + tile.height; 
					isGrounded = true;
				}
				velocity.y = 0;
				break;
			}
		}
		rectPool.freeAll(tiles); 
		
		this.position.add(velocity);
		this.velocity.scl(1/gameTime);
	}
	
	private void updateInput(float gameTime) {
		totalTime += gameTime;
		
		if (Gdx.input.isKeyPressed(Keys.SPACE) && this.isGrounded) {
			this.velocity.y += JUMP_VELOCITY;
			this.state = State.Jumping;
			this.isGrounded = false;
		}

		if (Gdx.input.isKeyPressed(Keys.LEFT)) {
			this.velocity.x = -MAX_VELOCITY;
			if (this.isGrounded)
				this.state = State.Walking;
			this.facesRight = false;
		}

		if (Gdx.input.isKeyPressed(Keys.RIGHT)) {
			this.velocity.x = MAX_VELOCITY;
			if (this.isGrounded)
				this.state = State.Walking;
			this.facesRight = true;
		}
	}

	@Override
	public void draw(SpriteBatch spriteBatch) {
		TextureRegion frame = null;
		switch (this.state) {
		case Standing:
			frame = stand.getKeyFrame(this.totalTime);
			break;
		case Walking:
			frame = walk.getKeyFrame(this.totalTime);
			break;
		case Jumping:
			frame = jump.getKeyFrame(this.totalTime);
			break;
		} 
		 
		if (this.facesRight) {
			spriteBatch.draw(frame, position.x, position.y, size.x, size.y);
		} else {
			spriteBatch.draw(frame, position.x + size.x, position.y, -size.x, size.y);
		} 
	}
	
	private Array<Rectangle> getTiles(int startX, int startY, int endX, int endY) {
		Array<Rectangle> tiles = new Array<Rectangle>();
		TiledMapTileLayer layer = (TiledMapTileLayer) map.getLayers().get(1); 
		
		for (int y = startY; y <= endY; y++) {
			for (int x = startX; x <= endX; x++) {
				Cell cell = layer.getCell(x, y);
				if (cell != null) {
					Rectangle rect = rectPool.obtain();
					rect.set(x, y, 1, 1);
					tiles.add(rect);
				}
			}
		}
		
		return tiles;
	}
}
